﻿using GTAFingerprinterCore.Keyboards;
using GTAFingerprinterCore.Pictures;
using GTAFingerprinterCore.Pictures.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GTAFingerprinterCore.Core
{
    public class Fingerprinter : IFingerprinter
    {
        public Dictionary<Image, List<Image>> BigAndSubsDic { get; set; }

        public Fingerprinter(string templateFolder)
        {
            if (!Directory.Exists(templateFolder))
            {
                throw new ArgumentException("模板文件夹不存在", nameof(templateFolder));
            }
            BigAndSubsDic = new Dictionary<Image, List<Image>>();
            var dirInfo = new DirectoryInfo(templateFolder);
            var files = dirInfo.GetFiles();
            foreach (var file in files)
            {
                var subs = new List<Image>();
                var subsDir = new DirectoryInfo(Path.Combine(file.DirectoryName, file.Name.Substring(0, file.Name.Length - 4)));
                foreach (var sub in subsDir.GetFiles())
                {
                    subs.Add(Image.FromFile(sub.FullName));
                }
                var big = Image.FromFile(file.FullName);
                BigAndSubsDic.Add(big, subs);
            }
        }

        public async Task AutoPressKeys(IEnumerable<int> corrects, int delay)
        {
            int tmpX = 0;
            int tmpY = 0;
            foreach (var item in corrects)
            {
                var x = item % 2;
                var y = item / 2;
                var dX = x - tmpX;
                var dY = y - tmpY;

                var cX = Math.Abs(dX);
                var cY = Math.Abs(dY);
                await Keyboarder.SendKey(dX >= 0 ? Keys.Right : Keys.Left, cX, delay: delay);
                await Keyboarder.SendKey(dY >= 0 ? Keys.Down : Keys.Up, cY, delay: delay);
                await Keyboarder.SendKey(Keys.Enter, delay: delay);

                tmpX = x;
                tmpY = y;
            }
            await Keyboarder.SendKey(Keys.Tab, delay: delay);
        }

        public async Task<Image> CaptureGameWindow(bool isFullScreen)
        {
            try
            {
                Image img;
                if (isFullScreen)
                {
                    img = await CaptureTool.CaptureScreen();
                }
                else
                {
                    img = await CaptureTool.CaptureWindow("Grand Theft Auto V");
                }
                var gameimg = Formatting(img);
                img.Dispose();
                return gameimg;
            }
            catch (Exception e)
            {
                throw e;
            }

        }

        public async Task<Image> CutBig(Image image, BigOption option)
        {
            return await Task.Run(() => image.Cut(option.X, option.Y, option.X + option.Width, option.Y + option.Height));
        }

        public async Task<List<Image>> CutSubs(Image image, SubsOption option)
        {
            List<Image> subs = new List<Image>();
            for (int i = 0; i < 8; i++)
            {
                var row = i / 2;
                var col = i % 2;
                var x1 = option.X + col * (option.SubWidth + option.SubSpace);
                var y1 = option.Y + row * (option.SubWidth + option.SubSpace);
                var x2 = x1 + option.SubWidth;
                var y2 = y1 + option.SubWidth;
                subs.Add(await Task.Run(() => image.Cut(x1, y1, x2, y2)));
            }
            return subs;
        }

        public Task<List<int>> Recognize(Image big, IEnumerable<Image> subs, float similarity)
        {
            double max = 0;
            Image cBig = null;
            foreach (var cKey in BigAndSubsDic.Keys)
            {
                var s = ImageDHash.Similarity(big, cKey);
                if (s > max)
                {
                    max = s;
                    cBig = cKey;
                }
            }
            var corrects = new List<int>();
            var subs2 = subs.ToList();
            foreach (var sub in subs2)
            {
                foreach (var cSub in BigAndSubsDic[cBig])
                {
                    if (ImageDHash.Similarity(sub, cSub) >= similarity)
                    {
                        corrects.Add(subs2.IndexOf(sub));
                        break;
                    }
                }
                if (corrects.Count == 4)
                {
                    break;
                }
            }
            return Task.FromResult(corrects);
        }

        public Image Formatting(Image img)
        {
            var ow = img.Width;
            var oh = img.Height;
            var nh = 720;
            var nw = (int)(ow / ((double)oh / 720));
            var resizeImg = img.Resize(nw, nh);
            if (nw != 1280)
            {
                return resizeImg.SetBorder((1280 - nw) / 2, BorderType.Left | BorderType.Right);
            }
            return resizeImg;
        }
    }
}